
//============================================================================
// Name        : GSPass-SatelliteTracker.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description :
//============================================================================

#include "SatelliteTracker.h"

namespace SatelliteTrackerSpace {
/**
* initiate a satellite tracker object
*/
SatelliteTracker::SatelliteTracker() {
		this->logger=Logger::getGSLogger();
		sband = NULL;
		vhfUhf = NULL;
		status=0;
}

SatelliteTracker::~SatelliteTracker() {
	if (sband != NULL)
		delete(sband);
	if (vhfUhf != NULL)
		delete (vhfUhf);
}
/**
* sets the antenna controller for SBAND
* sband - pointer to antenna controller
*/
void SatelliteTracker::setSBandController(IAntennaControllerBridge * sband)
{
	this->sband = sband;
}
/**
* sets the antenna controller for VHF/UHF
* vhfUhf - pointer to antenna controller
*/
void SatelliteTracker::setVHFUHFController(IAntennaControllerBridge * vhfUhf)
{
	this->vhfUhf=vhfUhf;
}

/**
 * initiatePosition - directs the antennas to the given AER
 * initAER - the direction to be pointed to
 */
bool SatelliteTracker::initiatePosition(SatelliteAER * initAER)
{

	if (!activateAntennas())
	{
		ProgressStatus status0(ProgressStatusType::ERR, "SatelliteTracker", "initiatePosition" , UNABLE_CONNECT_ANTENNA, true, false);
		logger->logError(status0);
		return false;
	}

	bool succeded= true;

	if (initAER == NULL)
	{
		ProgressStatus status1(ProgressStatusType::ERR, "SatelliteTracker", "initiatePosition" , OBJECT_IS_NULL, true, false);
		logger->logError(status1);
		return false;
	}

	if ( !sband->pointAntennaTo( initAER ) )
	{
		ProgressStatus status2(ProgressStatusType::ERR, "SatelliteTracker", "initiatePosition" , ERROR_DIRECTING_ANT +" " + sband->getControllerName()+ " to position: <" + float2str(initAER->getAzimuth()) + " : " + float2str(initAER->getElevation()) + ">", true, false);
		logger->logError(status2);
		succeded = false;
	}

	if ( !vhfUhf->pointAntennaTo( initAER ) )
	{
		ProgressStatus status3(ProgressStatusType::ERR, "SatelliteTracker", "initiatePosition" , ERROR_DIRECTING_ANT +" " + vhfUhf->getControllerName() + " to position: <" + float2str(initAER->getAzimuth()) + " : " + float2str(initAER->getElevation()) + ">", true, false);
		logger->logError(status3);
		succeded = false;
	}

	if (succeded)
	{
		ProgressStatus status(ProgressStatusType::INF, "SatelliteTracker", "initiatePosition" , ANTENNA_IN_DIR , true, false);
		logger->logInfo(status);
	}
	return succeded;
}

/*
 * Main method for tracking a satellite - send timed commands to antenna for tracking the satellite position.
 *
 * This method has to run in a separate thread in order for it to be able to switch satellites
 * during a pass, or to stop tracking completely.
 *
 * aerQ - a queue containing the predicted directions of the required satellite
 * timeToStartWith - the time when the tracking process should start at
 * passLogger - pointer to the pass logger that related to the current pass process.
 */
void SatelliteTracker::startTrackingSatellite(SatelliteAERQueue aerQ, long timeToStartWith, PassLogger * passLogger)
{
		try
		{

				status=0;
				ProgressStatus status0(ProgressStatusType::INF, "SatelliteTracker", "startTrackingSatellite" , START_TRACK , true, false);
				passLogger->logInfo(status0,true);

				SatelliteAER * instance = aerQ.popNextInstance();

				while (instance!= NULL && instance->getTimeStamp() < timeToStartWith)
				{
						delete(instance);
						instance = aerQ.popNextInstance();
						checkTrackerWatchDog();
				}

				if (instance == NULL)
				{
					ProgressStatus status1(ProgressStatusType::ERR, "SatelliteTracker", "startTrackingSatellite" , OBJECT_IS_NULL , true, false);
					passLogger->logError(status1,true);
					throw boost::thread_interrupted();
				}
				status++;

				while( instance != NULL && isTimeForInstace(instance))
				{
						checkTrackerWatchDog();
						float az = instance->getAzimuth(), el = instance->getElevation();
						ProgressStatus status2(ProgressStatusType::INF, "SatelliteTracker", "startTrackingSatellite" , AER_TIME+ getTimeStampOf(instance->getTimeStamp()) , false, false);
						passLogger->logInfo(status2,false);

						if (sband->pointAntennaTo( instance ) && vhfUhf->pointAntennaTo( instance ))
						{
							ProgressStatus status3(ProgressStatusType::INF, "SatelliteTracker", "startTrackingSatellite" , ANTENNA_IN_DIR + " <" + float2str(az) + " : " + float2str(el) + ">", false, false);
							passLogger->logInfo(status3,false);
						}
						else
						{
							ProgressStatus status4(ProgressStatusType::ERR, "SatelliteTracker", "startTrackingSatellite" , ERROR_DIRECTING_ANT + " <" + float2str(az) + " : " + float2str(el) + ">", false, false);
							passLogger->logError(status4,false);
						}

						instance = getNextInstanceByAntennaResolution(instance,&aerQ);
				}

				ProgressStatus status5(ProgressStatusType::INF, "SatelliteTracker", "startTrackingSatellite" ,STOP_TRACK, true, true);
				passLogger->logInfo(status5,LoggingColor::RED,true);
		}
		catch(boost::thread_interrupted&)
		{
			ProgressStatus status6(ProgressStatusType::WRN, "SatelliteTracker", "startTrackingSatellite" , INTERRUPTED, true, true);
			logger->logWarning(status6);
			reportStatus(passLogger);
			return;
		}
}


SatelliteAER *  SatelliteTracker::getNextInstanceByAntennaResolution(SatelliteAER * currentInstance,SatelliteAERQueue * aerQ)
{
	//TODO
	//if (CoreSettings::getInstance().isSimulateMode())
	//		return aerQ.popNextInstance();

	int rate = CoreSettings::getInstance().getAntennasRate();
	long currentTime = currentInstance->getTimeStamp();
	currentTime+=rate;
	delete(currentInstance);
	SatelliteAER * instance = aerQ->popNextInstance();

	while (instance!=NULL && instance->getTimeStamp() < currentTime)
	{
			instance = aerQ->popNextInstance();
	}

	return instance;
}

/**
 * activateAntennas - turning the antennas on and connecting to them
 */
bool SatelliteTracker::activateAntennas()
{
		if (!sband->isActive())
		{
			if (!sband->connect())
				return false;
		}

		if (!vhfUhf->isActive())
		{
			if (!vhfUhf->connect())
				return false;
		}

		return true;
}

/**
 * turnVHFOff - turning the VHF transmitter off
 */
void SatelliteTracker::turnVHFOff()
{
		vhfUhf->setIsActive(false);
}

bool SatelliteTracker::isTimeForInstace(SatelliteAER* instance)throw (boost::thread_interrupted&)
{
		timespec timespc;
		clock_gettime(CLOCK_REALTIME, &timespc);

		if (timespc.tv_sec<instance->getTimeStamp())
		{
				boost::this_thread::interruption_point();
				int timetosleep = instance->getTimeStamp()-timespc.tv_sec - 1;
				if (timetosleep>0)
					sleep(timetosleep);
		}

		return true;
}

void SatelliteTracker::checkTrackerWatchDog() throw (boost::thread_interrupted&)
{
		boost::this_thread::interruption_point();
}

void SatelliteTracker::reportStatus(PassLogger * passLogger)
{
	string info;
	switch(status)
	{
		case 0:
		{
			info = TRACK_INTERRUPT_0;
			break;
		}
		case 1:
		{
			info = TRACK_INTERRUPT_1;
			break;
		}
		case 2:
		{
			info = TRACK_INTERRUPT_2;
			break;
		}
		default:
		{
			info = PASS_INTERRUPT_DEF;
			info.append(int2str(status));
			info.append(".");
			break;
		}
	}
	status = 0;

	ProgressStatus status7(ProgressStatusType::INF, "SatelliteTracker", "reportStatus" ,info, true, false);
	passLogger->logInfo(status7,true);
}

}
